﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Roton.Video
{
    /// <summary>
    /// A set of 256 fixed size glyphs.
    /// </summary>
    class GlyphSet
    {
        private const Int32 MaskBlack = -0x01000000; //FF000000 signed
        private const Int32 MaskWhite = -0x00000001; //FFFFFFFF signed

        private int area;
        private int height;
        private byte[] rawGlyphData;
        private Int32[] rawGlyphMaskOff;
        private Int32[] rawGlyphMaskOn;
        private int width;

        /// <summary>
        /// Create a new GlyphSet with no data.
        /// </summary>
        public GlyphSet()
        {
            SetGlyphData(new byte[] { });
        }

        /// <summary>
        /// Create a new GlyphSet with the specified data.
        /// </summary>
        /// <param name="data">Raw glyph data.</param>
        public GlyphSet(byte[] data)
        {
            SetGlyphData(data);
        }

        /// <summary>
        /// Retrieve the background mask of a glyph.
        /// </summary>
        /// <param name="index">Index of the glyph to retrieve.</param>
        public Int32[] GetGlyphBackgroundMask(int index)
        {
            int maskIndex = index * width * height;
            Int32[] result = new Int32[area];
            Array.Copy(rawGlyphMaskOff, maskIndex, result, 0, area);
            return result;
        }

        /// <summary>
        /// Retrieve the glyph data.
        /// </summary>
        public byte[] GetGlyphData()
        {
            byte[] result = new byte[rawGlyphData.Length];
            Array.Copy(rawGlyphData, result, rawGlyphData.Length);
            return result;
        }

        /// <summary>
        /// Retrieve the foreground mask of a glyph.
        /// </summary>
        /// <param name="index">Index of the glyph to retrieve.</param>
        public Int32[] GetGlyphForegroundMask(int index)
        {
            int maskIndex = index * width * height;
            Int32[] result = new Int32[area];
            Array.Copy(rawGlyphMaskOn, maskIndex, result, 0, area);
            return result;
        }

        /// <summary>
        /// Fixed height of the glyph data.
        /// </summary>
        public int Height
        {
            get { return height; }
        }

        /// <summary>
        /// Set raw glyph data.
        /// </summary>
        /// <param name="value">Data to set.</param>
        public void SetGlyphData(byte[] value)
        {
            Array.Copy(value, rawGlyphData, value.Length);
            UpdateGlyphs();
        }

        /// <summary>
        /// Render the glyph masks for each glyph.
        /// </summary>
        private void UpdateGlyphs()
        {
            width = 8;
            height = rawGlyphData.Length / 256;
            area = width * height;

            rawGlyphMaskOff = new Int32[width * height * 256];
            rawGlyphMaskOn = new Int32[rawGlyphMaskOff.Length];
            int maskIndex = 0;
            int dataIndex = 0;

            for (int c = 0; c < 256; c++)
            {
                for (int y = 0; y < height; y++)
                {
                    int dataLine = rawGlyphData[dataIndex++];
                    for (int x = 0; x < width; x++)
                    {
                        bool bit = ((dataLine & 0x80) != 0);
                        rawGlyphMaskOff[maskIndex] = bit ? MaskBlack : MaskWhite;
                        rawGlyphMaskOn[maskIndex++] = bit ? MaskWhite : MaskBlack;
                        dataLine <<= 1;
                    }
                }
            }
        }

        /// <summary>
        /// Width of the glyph data.
        /// </summary>
        public int Width
        {
            get { return width; }
        }
    }
}
